//
//  WKWebViewEx.swift
//  
//
//  Created by tank on 2021/11/16.
//

import Foundation
import WebKit
import Logging

open class WKWebViewEx: WKWebView {
    public static let processPool = WKProcessPool()
    
    public static var testHtmlUrl: String? {
        guard let htmlPath = LibUI.shared.dataSource?.htmlPath else {
            return nil
        }
        
        return Bundle.main.path(forResource: "\(htmlPath)/test", ofType: ".html")
    }
    
    var logger = Logger(label: "LibUI.WKWebViewEx")
    
    public weak var delegate: WebViewDelegate?
    
    public weak var webViewUIDelegate: WebViewUIDelegate?
    
    public init(configuration: WKWebViewConfiguration? = nil, frame: CGRect = .zero) {
        logger.logLevel = .debug
        
        let wkConfig: WKWebViewConfiguration
        if let configuration = configuration {
            wkConfig = configuration
        } else {
            wkConfig = WKWebViewConfiguration()
            wkConfig.processPool = WKWebViewEx.processPool
            wkConfig.userContentController.add(AppScriptMessageHandler(), name: AppScriptMessageHandler.key)
            wkConfig.preferences.javaScriptCanOpenWindowsAutomatically = true
            wkConfig.websiteDataStore = .default()
        }
        
        super.init(frame: frame, configuration: wkConfig)
        
        if #available(iOS 16.4, *) {
            isInspectable = true
        }
        
        navigationDelegate = self
        uiDelegate = self
        
        wkConfig
            .userContentController
            .addUserScript(WKUserScript(source: "appVersion = \"\(Bundle.main.ex.appVersion)\"",
                                        injectionTime: .atDocumentStart,
                                        forMainFrameOnly: false))
        
        wkConfig
            .userContentController
            .addUserScript(WKUserScript(source: "primaryColor = \"\(Theme.shared.currentThemeData.primaryColor.ex.hexRGB)\"",
                                        injectionTime: .atDocumentStart,
                                        forMainFrameOnly: false))
        
        wkConfig
            .userContentController
            .addUserScript(WKUserScript(source: "statusBarHeight = \(UIApplication.shared.statusBarFrame.height)",
                                        injectionTime: .atDocumentStart,
                                        forMainFrameOnly: false))
    }
    
    public required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        logger.info("WKWebViewEx deinit")
    }
    
    public func load(url: String) {
        let absoluteH5Url = url.ex.absoluteH5Url
        if let url = URL(string: absoluteH5Url.ex.isUrlEncoded ? absoluteH5Url : absoluteH5Url.ex.encodeURI() ?? "") {
            load(URLRequest(url: url))
        }
    }
}

extension WKWebViewEx: WKNavigationDelegate {
    public func webView(_ webView: WKWebView,
                        decidePolicyFor navigationAction: WKNavigationAction,
                        decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let delegate = delegate else {
            decisionHandler(.allow)
            return
        }
        
        delegate.webView(self, decidePolicyFor: navigationAction, decisionHandler: decisionHandler)
    }
    
    public func webView(_ webView: WKWebView,
                        decidePolicyFor navigationResponse: WKNavigationResponse,
                        decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        guard let delegate = delegate else {
            decisionHandler(.allow)
            return
        }
        
        delegate.webView(self, decidePolicyFor: navigationResponse, decisionHandler: decisionHandler)
    }
    
    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        logger.info("webView didFinish")
        
        delegate?.webView(self, didFinish: navigation)
    }
    
    public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        logger.info("webView didFailProvisionalNavigation \(error.localizedDescription)")
        
        delegate?.webView(self, didFailProvisionalNavigation: navigation, withError: error)
    }
    
    public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        logger.info("webView didFail \(error.localizedDescription)")
        
        delegate?.webView(self, didFail: navigation, withError: error)
    }
}

extension WKWebViewEx: WKUIDelegate {
    public func webView(_ webView: WKWebView,
                        createWebViewWith configuration: WKWebViewConfiguration,
                        for navigationAction: WKNavigationAction,
                        windowFeatures: WKWindowFeatures) -> WKWebView? {
        if windowFeatures.width != nil || windowFeatures.height != nil {
            return Dialog.shared.open(url: nil, configuration: configuration)
        } else if let webViewUIDelegate = webViewUIDelegate {
            return webViewUIDelegate.webView(self, createWebViewWith: configuration, for: navigationAction, windowFeatures: windowFeatures)
        } else {
            return LibUI.shared.webViewUIDeleagte?.webView(self, createWebViewWith: configuration, for: navigationAction, windowFeatures: windowFeatures)
        }
    }
    
    public func webViewDidClose(_ webView: WKWebView) {
        guard let dialogView = webView.superview?.superview as? DialogView else {
            delegate?.webViewDidClose(self)
            return
        }
        
        Dialog.shared.closeDialog(dialogId: dialogView.id, buttonId: "")
    }
}
